package com.zyf.project.capchain.utils.cryptology;

import lombok.SneakyThrows;
import org.apache.commons.io.FileUtils;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;

import javax.crypto.Cipher;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @author Zhou Yifan
 */
public class EncryptUtils {

    private static final String ALGORITHM = "RSA";

    private static final String PUBLIC_PATH = "a.pub";

    private static final String PRIVATE_PATH = "a.pri";

    private EncryptUtils() {
    }

    /**
     * 生成密钥
     *
     * @param pubPath 公钥保存路径
     * @param priPath 私钥保存路径
     */
    @SneakyThrows
    public static void generateKey(String pubPath, String priPath) {
        // 1.获取密钥生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
        // 2.获取密钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        // 3.获取公钥
        PublicKey publicKey = keyPair.getPublic();
        // 4.获取私钥
        PrivateKey privateKey = keyPair.getPrivate();
        // 5.获得byte字节数组
        byte[] publicKeyEncoded = publicKey.getEncoded();
        byte[] privateKeyEncoded = privateKey.getEncoded();

        // 6.使用BASE64编码
        String publicKeyString = Encipher.base64Encode(publicKeyEncoded);
        String privateKeyString = Encipher.base64DecodeBytesToString(privateKeyEncoded);

        // 7.保存文件
        FileUtils.writeStringToFile(new File(pubPath), publicKeyString, StandardCharsets.UTF_8);
        FileUtils.writeStringToFile(new File(priPath), privateKeyString, StandardCharsets.UTF_8);
    }

    /**
     * 读取公钥文件
     *
     * @return 公钥
     */
    public static PublicKey getPublicKey() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
        // 1.读取文件
        String s = FileUtils.readFileToString(new File(PUBLIC_PATH), StandardCharsets.UTF_8);

        // 2.获取密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);

        // 3.构建密钥规范
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Encipher.base64DecodeStringToBytes(s));

        return keyFactory.generatePublic(x509EncodedKeySpec);
    }

    /**
     * 读取私钥文件
     *
     * @return 私钥
     */
    public static PrivateKey getPrivateKey() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
        // 1.读取文件
        String s = FileUtils.readFileToString(new File(PRIVATE_PATH), StandardCharsets.UTF_8);

        // 2.获取密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);

        // 3.构建密钥规范
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Encipher.base64DecodeStringToBytes(s));

        return keyFactory.generatePrivate(spec);
    }

    /**
     * 加密
     *
     * @param input 原文
     * @param key   密钥
     * @return 加密后的文字
     */
    @SneakyThrows
    public static @NotNull String encryptRSA(@NotNull String input, Key key) {
        // 1.创建加密的对象
        Cipher cipher = Cipher.getInstance(ALGORITHM);

        // 2.初始化加密
        cipher.init(Cipher.ENCRYPT_MODE, key);

        // 3.公钥加密
        byte[] bytes = cipher.doFinal(input.getBytes());

        return Encipher.base64Encode(bytes);
    }

    /**
     * 解密
     *
     * @param input 原文
     * @param key   密钥
     * @return 解密后的文字
     */
    @Contract("_, _ -> new")
    @SneakyThrows
    public static @NotNull String decryptRSA(String input, Key key) {
        // 1.创建加密的对象
        Cipher cipher = Cipher.getInstance(ALGORITHM);

        // 2.初始化加密
        cipher.init(Cipher.DECRYPT_MODE, key);

        // 3.由于密文base64编码
        byte[] decode = Encipher.base64DecodeStringToBytes(input);

        // 4.对密文解密
        byte[] bytes = cipher.doFinal(decode);

        return new String(bytes);
    }
}
